#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <vector>
#include <unistd.h>

using namespace std;

const int defaultnum = 5;

template <class T>
class CircleQueue
{
private:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

public:
    CircleQueue(int maxcap = defaultnum)
        : _maxcap(maxcap),
          _cirque(maxcap),
          _p_ind(0),
          _c_ind(0)
    {
        sem_init(&_space, 0, maxcap);
        sem_init(&_data, 0, 0);

        pthread_mutex_init(&_c_mutex,nullptr);
        pthread_mutex_init(&_p_mutex,nullptr);

    }

    void push(const T &data)
    {
        P(_space);
        pthread_mutex_lock(&_p_mutex);

        _cirque[_p_ind] = data;
        _p_ind++;
        _p_ind %= _maxcap;

        pthread_mutex_unlock(&_p_mutex);
        V(_data);
    }

    T pop()
    {
        P(_data);
        pthread_mutex_lock(&_c_mutex);

        T data = _cirque[_c_ind];
        _c_ind++;
        _c_ind %= _maxcap;

        pthread_mutex_unlock(&_c_mutex);
        V(_space);

        return data;
    }

    ~CircleQueue()
    {
        sem_destroy(&_space);
        sem_destroy(&_data);

        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);
    }

public:
// private:
    vector<T> _cirque;
    int _maxcap;

    sem_t _space;
    sem_t _data;

    int _p_ind;
    int _c_ind;

    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;

};